#pragma once

#include "shared.hpp"
#include "util.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <memory>
#include <optional>
#include <print>
#include <random>

namespace Thread::detail {
static inline thread_local Worker *t_worker{nullptr};

class Worker : util::Nocopyable {
  // 声明shared类友元
  friend class Shared;

public:
  explicit Worker(Shared *share, std::size_t worker_id)
      : __share(share), __worker_id(worker_id) {
    // 将自己添加到共享资源里
    __share->get_workers().push_back(this);
    t_worker = this;
  }

public:
  // worker主函数
  void run() {
    while (!__share->is_shutdown()) {
      std::optional<std::function<void()>> task;

      // 获取任务
      task = std::move(get_next_task());
      if (task.has_value()) {
        task.value()();
        continue;
      }

      // 任务窃取
      task = std::move(task_steal());
      if (task.has_value()) {
        task.value()();
        continue;
      }

      std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
  }

public:
  bool local_empty() { return __localqueue.empty(); }
  bool priority_empty() { return __priorityqueue.empty(); }
  std::size_t local_size() {
    return __localqueue.size() + __priorityqueue.size();
  }

  // 本地队列单push,带队满处理
  void global_push_back(std::function<void()> func) {

    __share->push_global_task(func);
  }
  void local_push_back_maybe_overflow(std::function<void()> func) {
    __localqueue.push_back_maybe_overflow(func, __share->globalqueue());
  }

  // 本地队列多push,队满直接抛出异常
  void local_push_back_batch(std::span<std::function<void()>> funcs) {
    __localqueue.push_back_batch(funcs);
  }

  // 本地队列单push,队满直接抛出异常
  void priority_push_back(std::function<void()> func) {
    if (!__priorityqueue.push_back(func)) {
      throw std::runtime_error("priorityqueue push_back overflow!");
    }
  }

  // 优先级队列多push,队满直接抛出异常,
  void priority_push_back_batch(std::span<std::function<void()>> funcs) {
    __priorityqueue.push_back_batch(funcs);
  }

private:
  // 获取下一个本地队列任务
  std::optional<std::function<void()>> get_next_local_task() {
    // 优先从优先级队列获取
    if (!__priorityqueue.empty()) {
      return __priorityqueue.pop();
    }
    // 然后从本地队列获取
    return __localqueue.pop();
  }

  /* 功能：获取下一个任务
   *  总的获取顺序 本地 ->  全局
   *  对于全局队列 :
   *  1.n值，取本地队列剩余大小和本地队列一半容量之前的最小值
   *  2.如果等于0，说明本地队列无法被添加，直接从全局队列返回一个
   *  3.再取n和全局队列任务公平分配的数量的最小值
   *  4.选择第一个任务返回，其余批量从全局队列转移到本地队列
   */
  std::optional<std::function<void()>> get_next_task() {
    std::optional<std::function<void()>> next_task;
    // 先获取本地队列任务
    next_task = get_next_local_task();
    if (next_task.has_value()) {
      return next_task;
    }
    if (__share->global_empty()) {
      return std::nullopt;
    }

    // 取本地队列剩余大小和队列容量的一半的最小值
    auto n = std::min(__localqueue.remain_size(), __localqueue.capacity() / 2);
    if (n == 0) {
      next_task = __share->get_next_global_task();
      if (next_task.has_value()) {
        return next_task;
      }
    }
    //__share.__globalqueue.size() / __share.__workers.size()
    // 全局队列任务数/工作数，就是平均分配
    n = std::min(
        (__share->globalqueue().size() + 1) / __share->get_workers().size(), n);
    // 至少是1
    n = std::max(n, static_cast<std::size_t>(1));
    // 批量获取
    auto tasks = __share->get_global_task_batch(n);
    if (tasks.empty()) {
      return std::nullopt;
    }
    // 选择vector的第一个元素返回
    auto result = std::move(tasks.front());
    tasks.erase(tasks.begin());
    n -= 1;
    if (n > 0) {
      // 批量推入
      __localqueue.push_back_batch(tasks);
    }
    return result;
  }

  // 任务窃取逻辑
  std::optional<std::function<void()>> task_steal() {
    auto workers_num = __share->get_workers().size();
    // static thread_local 确保每个线程有独立的生成器实例，且只初始化一次
    static thread_local std::random_device rd; // 硬件随机数种子生成器
    static thread_local std::mt19937 gen(
        rd()); // 梅森旋转算法生成器，高质量随机数

    // 创建均匀分布生成器，范围是 [0, num-1]
    std::uniform_int_distribution<std::size_t> dis(0, workers_num - 1);
    auto start = dis(gen); // 生成随机起始索引

    // 环形遍历所有其他工作线程
    for (std::size_t i = 0; i < workers_num; ++i) {
      // 计算当前要检查的工作线程索引
      // 使用模运算实现环形遍历：从随机起始点开始，依次检查每个线程
      auto idx = (start + i) % workers_num;
      // 跳过自己 - 不能从自己的队列中窃取任务
      if (idx == __worker_id) {
        continue;
      }

      // 尝试从目标工作线程的本地队列中窃取任务
      if (auto result =
              __localqueue.steal_to(__share->get_workers()[idx]->__localqueue);
          result) {
        // 窃取成功！返回第一个任务用于执行
        // 其余窃取的任务已经被放入当前线程的本地队列中
        return result;
      }
    }
    // 如果所有工作线程都无法窃取到任务，返回空值
    return std::nullopt;
  }

private:
  std::size_t __worker_id;                 // worker的索引id
  detail::Shared *__share;                 // 共享资源
  util::LocalQueue<1024> __localqueue{};   // 本地队列
  util::LocalQueue<128> __priorityqueue{}; // 最高优先级队列
};
} // namespace Thread::detail